package nobnak.study.gl.projection;

import android.graphics.Bitmap;
import android.graphics.Color;


public class Triangle {
	public static final int TRIANGLE_VERTICES_COUNT = 3;
	public static final int VERTEX_DIMENSION = 4;
	public static final int UV_DIMENSION = 2;
	public static final float EPSILON = 1e-6f;
	public static final float HALF_PIXEL = 0.5f;
	
	public final float[] vertices;
	public final float[] uv;
	public final Bitmap texture;
	private int width;
	private int height;

	private float[] boundX = new float[2];
	private float[] boundY = new float[2];
	private float[] e1 = new float[2];
	private float[] e2 = new float[2];
	private float[] b = new float[2];
	
	// Constructors
	public Triangle(float[] vertices, float[] uv, Bitmap texture) {
		this.vertices = vertices;
		this.uv = uv;
		this.texture = texture;
		this.width = texture.getWidth();
		this.height = texture.getHeight();
		TriangleUtil.bound(boundX, boundY, vertices);
	}
	
	public int bilinear(float u, float v) {
		float x = width * u - HALF_PIXEL;
		float y = height * (1-v) - HALF_PIXEL;
		int ix = (int) Math.floor(x);
		int iy = (int) Math.floor(y);
		float dx = x - ix;
		float dy = y - iy;
		int c00 = getPixel(ix, iy);
		int c10 = getPixel(ix + 1, iy);
		int c01 = getPixel(ix, iy + 1);
		int c11 = getPixel(ix + 1, iy + 1);
		return Color.argb(
				TriangleUtil.blend(dx, dy, Color.alpha(c00), Color.alpha(c01), Color.alpha(c10), Color.alpha(c11)),
				TriangleUtil.blend(dx, dy, Color.red(c00), Color.red(c01), Color.red(c10), Color.red(c11)),
				TriangleUtil.blend(dx, dy, Color.green(c00), Color.green(c01), Color.green(c10), Color.green(c11)),
				TriangleUtil.blend(dx, dy, Color.blue(c00), Color.blue(c01), Color.blue(c10), Color.blue(c11)));
	}
	public int getPixel(int x, int y) {
		x = (x >= width ? width - 1 : x);
		x = (x < 0 ? 0 : x);
		y = (y >= height ? height - 1 : y);
		y = (y < 0 ? 0 : y);
		return texture.getPixel(x, y);
	}
	public boolean hit(float[] outP, float[] outUv, float x, float y) {
		if (!inbound(x, y))
			return false;
		
		e1[0] = vertices[1 * VERTEX_DIMENSION] - vertices[0];
		e1[1] = vertices[1 * VERTEX_DIMENSION + 1] - vertices[1];
		e2[0] = vertices[2 * VERTEX_DIMENSION] - vertices[0];
		e2[1] = vertices[2 * VERTEX_DIMENSION + 1] - vertices[1];
		float d = TriangleUtil.det(e1, e2);
		b[0] = x - vertices[0];
		b[1] = y - vertices[1];

		float s = TriangleUtil.det(b, e2) / d;
		if (s < 0 || 1 < s)
			return false;
		float t = TriangleUtil.det(e1, b) / d;
		if (t < 0 || 1 < t)
			return false;
		float upv = s + t;
		if (upv > 1)
			return false;

		outUv[0] = (1 - upv) * uv[0] + s * uv[2] + t * uv[4];
		outUv[1] = (1 - upv) * uv[1] + s * uv[3] + t * uv[5];

		outP[0] = x;
		outP[1] = y; 
		outP[2] = (1 - upv) * vertices[2] 
				+ s * vertices[1 * VERTEX_DIMENSION + 2]
				+ t * vertices[2 * VERTEX_DIMENSION + 2];
		return true;
	}
	public boolean inbound(float x, float y) {
		return (boundX[0] <= x && x <= boundX[1] && boundY[0] <= y && y <= boundY[1]);
	}
	public Triangle muliply(float[] matrix, int offsetM) {
		float[] result = new float[TRIANGLE_VERTICES_COUNT * VERTEX_DIMENSION];
		for (int i = 0; i < TRIANGLE_VERTICES_COUNT; i++)
			MatrixMath.multiplyVector(result, i * 4, matrix, offsetM, vertices, i * 4);
		for (int i = 0; i < TRIANGLE_VERTICES_COUNT; i++) {
			int offsetVertex = i * VERTEX_DIMENSION;
			for (int j = 0; j < VERTEX_DIMENSION; j++)
				result[offsetVertex + j] /= result[offsetVertex + VERTEX_DIMENSION - 1];
		}
		return new Triangle(result, uv, texture);
	}
}
